From bb9626dc292edbd7a624c9b0ce921c2767612ba9 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Tue, 8 Nov 2016 01:42:06 +0100 Subject: [PATCH] window: Implement snapshot() --- gtk/gtkcontainer.c | 117 ++++++++++++++++++++++++----------- gtk/gtkcontainerprivate.h | 4 ++ gtk/gtkdebugupdates.c | 9 ++- gtk/gtkdebugupdatesprivate.h | 4 +- gtk/gtksnapshot.c | 13 ++++ gtk/gtksnapshotprivate.h | 10 +++ gtk/gtkwidget.c | 3 + gtk/gtkwindow.c | 30 ++++++--- 8 files changed, 137 insertions(+), 53 deletions(-) diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c index a68fa8708c..893b1e43c0 100644 --- a/gtk/gtkcontainer.c +++ b/gtk/gtkcontainer.c @@ -42,6 +42,7 @@ #include "gtkmarshalers.h" #include "gtksizerequest.h" #include "gtksizerequestcacheprivate.h" +#include "gtksnapshotprivate.h" #include "gtkwidgetprivate.h" #include "gtkwindow.h" #include "gtkassistant.h" @@ -3158,47 +3159,16 @@ gtk_container_get_children_clip (GtkContainer *container, gtk_container_forall (container, union_with_clip, out_clip); } -/** - * gtk_container_propagate_draw: - * @container: a #GtkContainer - * @child: a child of @container - * @cr: Cairo context as passed to the container. If you want to use @cr - * in container’s draw function, consider using cairo_save() and - * cairo_restore() before calling this function. - * - * When a container receives a call to the draw function, it must send - * synthetic #GtkWidget::draw calls to all children that don’t have their - * own #GdkWindows. This function provides a convenient way of doing this. - * A container, when it receives a call to its #GtkWidget::draw function, - * calls gtk_container_propagate_draw() once for each child, passing in - * the @cr the container received. - * - * gtk_container_propagate_draw() takes care of translating the origin of @cr, - * and deciding whether the draw needs to be sent to the child. It is a - * convenient and optimized way of getting the same effect as calling - * gtk_widget_draw() on the child directly. - * - * In most cases, a container can simply either inherit the - * #GtkWidget::draw implementation from #GtkContainer, or do some drawing - * and then chain to the ::draw implementation from #GtkContainer. - **/ -void -gtk_container_propagate_draw (GtkContainer *container, - GtkWidget *child, - cairo_t *cr) +static void +gtk_container_get_translation_to_child (GtkContainer *container, + GtkWidget *child, + int *x_out, + int *y_out) { GtkAllocation allocation; GdkWindow *window, *w; int x, y; - g_return_if_fail (GTK_IS_CONTAINER (container)); - g_return_if_fail (GTK_IS_WIDGET (child)); - g_return_if_fail (cr != NULL); - g_return_if_fail (_gtk_widget_get_parent (child) == GTK_WIDGET (container)); - - if (!gtk_container_should_propagate_draw (container, child, cr)) - return; - /* translate coordinates. Ugly business, that. */ if (!_gtk_widget_get_has_window (GTK_WIDGET (container))) { @@ -3235,6 +3205,51 @@ gtk_container_propagate_draw (GtkContainer *container, y += allocation.y; } + *x_out = x; + *y_out = y; +} + +/** + * gtk_container_propagate_draw: + * @container: a #GtkContainer + * @child: a child of @container + * @cr: Cairo context as passed to the container. If you want to use @cr + * in container’s draw function, consider using cairo_save() and + * cairo_restore() before calling this function. + * + * When a container receives a call to the draw function, it must send + * synthetic #GtkWidget::draw calls to all children that don’t have their + * own #GdkWindows. This function provides a convenient way of doing this. + * A container, when it receives a call to its #GtkWidget::draw function, + * calls gtk_container_propagate_draw() once for each child, passing in + * the @cr the container received. + * + * gtk_container_propagate_draw() takes care of translating the origin of @cr, + * and deciding whether the draw needs to be sent to the child. It is a + * convenient and optimized way of getting the same effect as calling + * gtk_widget_draw() on the child directly. + * + * In most cases, a container can simply either inherit the + * #GtkWidget::draw implementation from #GtkContainer, or do some drawing + * and then chain to the ::draw implementation from #GtkContainer. + **/ +void +gtk_container_propagate_draw (GtkContainer *container, + GtkWidget *child, + cairo_t *cr) +{ + int x, y; + + g_return_if_fail (GTK_IS_CONTAINER (container)); + g_return_if_fail (GTK_IS_WIDGET (child)); + g_return_if_fail (cr != NULL); + g_return_if_fail (_gtk_widget_get_parent (child) == GTK_WIDGET (container)); + + if (!gtk_container_should_propagate_draw (container, child, cr)) + return; + + gtk_container_get_translation_to_child (container, child, &x, &y); + cairo_save (cr); cairo_translate (cr, x, y); @@ -3243,6 +3258,36 @@ gtk_container_propagate_draw (GtkContainer *container, cairo_restore (cr); } +void +gtk_container_snapshot_child (GtkContainer *container, + GskRenderNode *container_node, + GtkWidget *child, + const GtkSnapshot *snapshot) +{ + GtkSnapshot child_snapshot; + GskRenderNode *child_node; + int x, y; + + g_return_if_fail (GTK_IS_CONTAINER (container)); + g_return_if_fail (GTK_IS_WIDGET (child)); + g_return_if_fail (_gtk_widget_get_parent (child) == GTK_WIDGET (container)); + g_return_if_fail (GSK_IS_RENDER_NODE (container_node)); + g_return_if_fail (snapshot != NULL); + + gtk_container_get_translation_to_child (container, child, &x, &y); + + gtk_snapshot_init_translate (&child_snapshot, snapshot, x, y); + child_node = gtk_widget_snapshot (child, &child_snapshot); + + if (child_node) + { + gsk_render_node_append_child (container_node, child_node); + gsk_render_node_unref (child_node); + } + + gtk_snapshot_finish (&child_snapshot); +} + /** * gtk_container_get_path_for_child: * @container: a #GtkContainer diff --git a/gtk/gtkcontainerprivate.h b/gtk/gtkcontainerprivate.h index c106ab8516..7b0b9e45cb 100644 --- a/gtk/gtkcontainerprivate.h +++ b/gtk/gtkcontainerprivate.h @@ -50,6 +50,10 @@ void gtk_container_propagate_render_node_for_child (GtkContainer *contai GtkWidget *child, GskRenderer *renderer, GskRenderNode *parent_node); +void gtk_container_snapshot_child (GtkContainer *container, + GskRenderNode *container_node, + GtkWidget *child, + const GtkSnapshot *snapshot); G_END_DECLS diff --git a/gtk/gtkdebugupdates.c b/gtk/gtkdebugupdates.c index 42e89b6b19..752a9c41f1 100644 --- a/gtk/gtkdebugupdates.c +++ b/gtk/gtkdebugupdates.c @@ -265,8 +265,8 @@ gtk_debug_updates_queue_get_extents (GQueue *updates, } GskRenderNode * -gtk_debug_updates_get_render_node (GtkWidget *widget, - GskRenderer *renderer) +gtk_debug_updates_snapshot (GtkWidget *widget, + const GtkSnapshot *snapshot) { GQueue *updates; GskRenderNode *node; @@ -287,12 +287,11 @@ gtk_debug_updates_get_render_node (GtkWidget *widget, gtk_debug_updates_print (updates, NULL, "Painting at %lli", (long long) timestamp); - node = gsk_renderer_create_render_node (renderer); - gsk_render_node_set_name (node, "Debug Updates"); + node = gtk_snapshot_create_render_node (snapshot, "Debug Updates"); gtk_debug_updates_queue_get_extents (updates, &rect); gsk_render_node_set_bounds (node, &(graphene_rect_t) GRAPHENE_RECT_INIT(rect.x, rect.y, rect.width, rect.height)); - cr = gsk_render_node_get_draw_context (node, renderer); + cr = gsk_render_node_get_draw_context (node, gtk_snapshot_get_renderer (snapshot)); for (l = g_queue_peek_head_link (updates); l != NULL; l = l->next) { diff --git a/gtk/gtkdebugupdatesprivate.h b/gtk/gtkdebugupdatesprivate.h index 713411951c..2e55ea4555 100644 --- a/gtk/gtkdebugupdatesprivate.h +++ b/gtk/gtkdebugupdatesprivate.h @@ -31,8 +31,8 @@ void gtk_debug_updates_set_enabled_for_display (GdkDisplay void gtk_debug_updates_add (GtkWidget *widget, const cairo_region_t *region); -GskRenderNode * gtk_debug_updates_get_render_node (GtkWidget *widget, - GskRenderer *renderer); +GskRenderNode * gtk_debug_updates_snapshot (GtkWidget *widget, + const GtkSnapshot *snapshot); G_END_DECLS diff --git a/gtk/gtksnapshot.c b/gtk/gtksnapshot.c index 0dbc3d1b76..d2507458c4 100644 --- a/gtk/gtksnapshot.c +++ b/gtk/gtksnapshot.c @@ -31,6 +31,19 @@ gtk_snapshot_init (GtkSnapshot *state, graphene_matrix_init_from_matrix (&state->transform, transform); } +void +gtk_snapshot_init_translate (GtkSnapshot *state, + const GtkSnapshot *parent, + int x, + int y) +{ + graphene_matrix_t matrix; + + graphene_matrix_init_translate (&matrix, &(graphene_point3d_t) GRAPHENE_POINT3D_INIT (x, y, 0)); + + gtk_snapshot_init (state, parent, &matrix); +} + void gtk_snapshot_init_root (GtkSnapshot *state, GskRenderer *renderer) diff --git a/gtk/gtksnapshotprivate.h b/gtk/gtksnapshotprivate.h index 5b238b74d2..bb8df07964 100644 --- a/gtk/gtksnapshotprivate.h +++ b/gtk/gtksnapshotprivate.h @@ -33,9 +33,19 @@ struct _GtkSnapshot { void gtk_snapshot_init (GtkSnapshot *state, const GtkSnapshot *parent, const graphene_matrix_t *transform); +void gtk_snapshot_init_translate (GtkSnapshot *state, + const GtkSnapshot *parent, + int x, + int y); void gtk_snapshot_init_root (GtkSnapshot *state, GskRenderer *renderer); +static inline const graphene_matrix_t * +gtk_snapshot_get_transform (const GtkSnapshot *snapshot) +{ + return &snapshot->transform; +} + void gtk_snapshot_finish (GtkSnapshot *state); G_END_DECLS diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 562c5ee6ba..e35e663102 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -15742,6 +15742,9 @@ gtk_widget_snapshot (GtkWidget *widget, } } + if (node) + gsk_render_node_set_transform (node, gtk_snapshot_get_transform (snapshot)); + return node; } diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 79d7aa4d32..5f550d270c 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -447,8 +447,8 @@ static void gtk_window_real_activate_focus (GtkWindow *window); static void gtk_window_keys_changed (GtkWindow *window); static gboolean gtk_window_enable_debugging (GtkWindow *window, gboolean toggle); -static GskRenderNode *gtk_window_get_render_node (GtkWidget *widget, - GskRenderer *renderer); +static GskRenderNode *gtk_window_snapshot (GtkWidget *widget, + const GtkSnapshot *snapshot); static void gtk_window_unset_transient_for (GtkWindow *window); static void gtk_window_transient_parent_realized (GtkWidget *parent, GtkWidget *window); @@ -776,7 +776,7 @@ gtk_window_class_init (GtkWindowClass *klass) widget_class->measure = gtk_window_measure; widget_class->state_flags_changed = gtk_window_state_flags_changed; widget_class->style_updated = gtk_window_style_updated; - widget_class->get_render_node = gtk_window_get_render_node; + widget_class->snapshot = gtk_window_snapshot; widget_class->queue_draw_region = gtk_window_queue_draw_region; container_class->remove = gtk_window_remove; @@ -9384,8 +9384,8 @@ gtk_window_compute_hints (GtkWindow *window, ***********************/ static GskRenderNode * -gtk_window_get_render_node (GtkWidget *widget, - GskRenderer *renderer) +gtk_window_snapshot (GtkWidget *widget, + const GtkSnapshot *snapshot) { GtkWindowPrivate *priv = GTK_WINDOW (widget)->priv; GtkStyleContext *context; @@ -9397,6 +9397,7 @@ gtk_window_get_render_node (GtkWidget *widget, graphene_matrix_t m; graphene_point3d_t p; cairo_t *cr; + GList *l; context = gtk_widget_get_style_context (widget); @@ -9406,12 +9407,11 @@ gtk_window_get_render_node (GtkWidget *widget, graphene_rect_init (&bounds, allocation.x, allocation.y, allocation.width, allocation.height); graphene_matrix_init_translate (&m, graphene_point3d_init (&p, allocation.x, allocation.y, 0.)); - node = gsk_renderer_create_render_node (renderer); - gsk_render_node_set_name (node, "Window Decoration"); + node = gtk_snapshot_create_render_node (snapshot, "Window Decoration"); gsk_render_node_set_bounds (node, &bounds); gsk_render_node_set_transform (node, &m); - cr = gsk_render_node_get_draw_context (node, renderer); + cr = gsk_render_node_get_draw_context (node, gtk_snapshot_get_renderer (snapshot)); if (priv->client_decorated && priv->decorated && @@ -9478,9 +9478,19 @@ gtk_window_get_render_node (GtkWidget *widget, cairo_destroy (cr); - gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, node); + if (priv->title_box != NULL) + gtk_container_snapshot_child (GTK_CONTAINER (widget), node, priv->title_box, snapshot); + + if (gtk_bin_get_child (GTK_BIN (widget))) + gtk_container_snapshot_child (GTK_CONTAINER (widget), node, gtk_bin_get_child (GTK_BIN (widget)), snapshot); + + for (l = priv->popovers; l; l = l->next) + { + GtkWindowPopover *data = l->data; + gtk_container_snapshot_child (GTK_CONTAINER (widget), node, data->widget, snapshot); + } - updates_node = gtk_debug_updates_get_render_node (widget, renderer); + updates_node = gtk_debug_updates_snapshot (widget, snapshot); if (updates_node) { gsk_render_node_append_child (node, updates_node); -- 2.30.2